Modifying original code

Original file: Fig3_4_6_ExtFig5-6-10_RPM_RPMA_Allos_CellTag.R Fig3_4_6_ExtFig5-6-10_RPM_RPMA_Allos_CellTag.R file on GitHub

This notebook is modified from the original code to remove the preprocessing steps and show figures inline within the notebook.

There is a separate notebook for the CellTag analysis.

Load the Seurat object and CellTag clones

TBO_seurat<-readRDS("../data/05_2025_RPM_RPMA_TBO_CellTag_Seurat_wSigs_FA_dpt_final.rds")
TBO_seurat
An object of class Seurat 
110982 features across 26618 samples within 2 assays 
Active assay: RNA (55491 features, 0 variable features)
 2 layers present: counts, data
 1 other assay present: norm
 2 dimensional reductions calculated: umap, fa
clones <- readRDS("../data/05_2025_RPM_RPMA_TBOAllo_CellTagClones_Onlyclones.rds")
clones
An object of class Seurat 
110982 features across 5965 samples within 2 assays 
Active assay: RNA (55491 features, 0 variable features)
 2 layers present: counts, data
 1 other assay present: norm
 2 dimensional reductions calculated: umap, fa

Load organoid data as SingleCellExperiment

sce <- as.SingleCellExperiment(TBO_seurat, assay = "norm")
phenotypes <- as.character(unique(sce@colData@listData$Pheno))
pheno_pairs_list <- combn(phenotypes, 2, simplify = FALSE)

Define color palettes

my_colors <- c(
  "#E41A1C", # strong red
  "#377EB8", # medium blue
  "#4DAF4A", # green
  "#984EA3", # purple
  "#FF7F00", # orange
  "#FFFF33", # yellow
  "#A65628", # brown
  "#e7298a", # pink
  "#666666", # grey
  "#66C2A5", # teal
  "#FC8D62", # salmon
  "#8DA0CB", # soft blue
  "#E78AC3", # soft pink (different from 8)
  "#A6D854", # light green (but yellowish tint, not green)
  "#FFD92F", # lemon yellow
  "#E5C494", # light brown
  "#B3B3B3", # light grey
  "#1B9E77", # deep teal
  "#D95F02", # dark orange
  "#7570B3", # strong purple
  "#66A61E"  # olive green (NOT same green as before)
)

Define function to plot violin plots by phenotype

Copied from 02_WT_RPM_Organoids_Allografts_notebook.Rmd

Needs SingleCellExperiment sce object and pheno_pairs_list defined in the notebook.

plotVlnByPhen <- function(feature, yl=c(-0.1,0.3), focus=NA) {
    if(!is.na(focus)) {
        pheno_pairs_list <- pheno_pairs_list[sapply(pheno_pairs_list, function(x) focus %in% x)]
    }
    
    scater::plotColData(sce, x = "Pheno", y = feature, colour_by = "Pheno") + 
        scale_discrete_manual(aesthetics = c("colour", "fill"), values=pheno_col) +
        theme(axis.title.y = element_text(size = 24), axis.text.y = element_text(size = 16),
              axis.text.x = element_blank(),   # rotate x-axis labels
              plot.title = element_blank(),    # remove plot title
              legend.position = "none"         # remove legend
        ) + labs(x = "",                     # custom x-axis title
                 y = "Signature score"        # custom y-axis title
        ) + ylim(yl[1], yl[2]) + 
        geom_boxplot(fill=pheno_col, alpha=1/5, position = position_dodge(width = .2),
                     size=0.2, color="black", notch=TRUE, notchwidth=0.3, outlier.shape = 2, outlier.colour=NA) # + 
        # stat_summary(fun = mean,
        #              geom = "point",
        #              shape = 18,
        #              size = 2,
        #              color = "red",
        #              position = position_dodge(width = 0.5)) + 
        # ggpubr::stat_compare_means(method = "wilcox.test", label = "p.signif", size=4, 
        #                            vjust = 0.5,
        #                            hide.ns = TRUE, comparisons = pheno_pairs_list)
}

Fig. 2e UMAP

DimPlot(TBO_seurat, group.by='Genotype', cols=c("darkorchid4","orange"),
        pt.size = 0.1,
        reduction='umap', label=FALSE, label.size=7, shuffle=TRUE) & NoAxes()

Fig. 2f (UMAP by Leiden cluster)

DimPlot(TBO_seurat, group.by='leiden_scVI_1.2', 
        cols=my_colors, reduction='umap', label=TRUE, label.size=5,
        pt.size = 0.1) & NoAxes() +
    theme(legend.position="none")

Idents(TBO_seurat) <- 'leiden_scVI_1.2'

x <- table(TBO_seurat@meta.data$Genotype,Idents(TBO_seurat))
proportions <- as.data.frame(100*prop.table(x, margin = 1))

colnames(proportions) <- c("Sample", "Cluster", "Frequency")

# ggpubr::ggbarplot(proportions, x="Sample", y="Frequency", fill = "Sample", group = "Sample",
#                   ylab = "Frequency (percent)", xlab="Phase", palette =c("indianred3","green3","royalblue4")) +
#     theme_bw() + facet_wrap(facets = "Cluster", scales="free_y", ncol =4) +
#     theme(axis.text.y = element_text(size=6)) + ggpubr::rotate_x_text(angle = 45)

Fig 2f

# Stacked
p <- ggplot(proportions, aes(fill=Cluster, y=Frequency, x=Sample)) + 
    geom_bar(position="stack", stat="identity")

p + scale_fill_manual(values=my_colors) + theme_bw() + 
    theme(axis.text.y = element_text(size=16), 
          axis.text.x = element_text(size=16, angle = 90, vjust = 0.5, hjust=1), 
          axis.title.x = element_text(size=16), axis.title.y = element_text(size=16), 
          legend.text = element_text(size=12), legend.title = element_blank()) + 
    labs(x = NULL, y = "Sample composition (%)")

Fig. 2h

UMAP colored by SCLC fate

# Define fate color vector and use to plot by cell state
pheno_col <- c("brown2","darkorchid4","dodgerblue","#66A61E","orange","turquoise4","turquoise")
DimPlot(TBO_seurat, group.by='Pheno', cols=pheno_col, reduction='umap', label=FALSE, 
        shuffle=TRUE, label.size=6) & NoAxes()

Fig. 2h (stacked barplot by Pheno)

Idents(TBO_seurat) <-'Pheno'

x <- table(TBO_seurat@meta.data$Genotype,Idents(TBO_seurat))
proportions <- as.data.frame(100*prop.table(x, margin = 1))

colnames(proportions)<-c("Cluster", "Sample", "Frequency")

p <- ggplot(proportions, aes(fill=Sample, y=Frequency, x=Cluster)) + 
    geom_bar(position="stack", stat="identity")

p + scale_fill_manual(values=pheno_col) + theme_bw() + 
    theme(axis.text.y = element_text(size=20), 
          axis.text.x=element_text(size=20, angle = 90, hjust = 1, vjust = 0.5), 
          axis.title.x = element_text(size=20), axis.title.y = element_text(size=20), 
          legend.text = element_text(size=20), legend.title = element_text(size=20)) + 
    labs(x = NULL)

Fig. 2i UMAP

NE score (correlation)

FeaturePlot(TBO_seurat, features = c("NE_spearman"), pt.size=0.2,
            reduction='umap') + viridis::scale_color_viridis(option="rocket",direction=-1) & NoAxes()

Fig 2i (violin plots of NE score by SCLC fate)

plotVlnByPhen("NE_spearman", yl=c(-.7, .8))

Fig 2i (violin plots of NE score by genotype)

x <- scater::plotColData(sce, x = "Genotype", y = "NE_spearman", colour_by = "Genotype") + 
    scale_discrete_manual(aesthetics = c("colour", "fill"), values=c("darkorchid4","orange"))

x <- x + theme(axis.title.y = element_text(size = 24),axis.text.y = element_text(size = 16), 
               axis.text.x = element_blank(), 
               # plot.title = element_blank(),
               legend.position = "none") + labs(x = "",  y = "Signature score") +  ylim(-1,1) + 
    geom_boxplot(fill=c("darkorchid4","orange"), alpha=1/5, 
                 position = position_dodge(width = .2), size=0.2,
                 color="black", notch=TRUE, notchwidth=0.3, outlier.shape = 2, outlier.colour=NA)

## Perform wilcoxon rank-sum test for RPM vs RPMA on the NE score data (Fig. 3i) ##
x + stat_summary(fun = mean,
                 geom = "point",
                 shape = 18,
                 size = 2,
                 color = "red",
                 position = position_dodge(width = 0.9)) + 
    ggpubr::stat_compare_means(method = "wilcox.test",label = "p.signif", 
                               hide.ns = TRUE,comparisons = list(c("RPM", "RPMA")))

Fig. 2j

Fig 2j (UMAP marker gene expression)

Equivalent color schemes:
* viridis::scale_color_viridis(option="rocket", direction=-1)
* scale_color_gradientn(colors=viridis::rocket(10, direction=-1))

# TF target gene scores in UMAP
FeaturePlot(TBO_seurat, features = c("ASCL1_Targets1"), pt.size=0.2, 
            reduction='umap') + viridis::scale_color_viridis(option="rocket",direction=-1) & NoAxes()

FeaturePlot(TBO_seurat, features = c("NEUROD1_Targets1"), pt.size=0.2,
            reduction='umap') + viridis::scale_color_viridis(option="rocket",direction=-1) & NoAxes()

FeaturePlot(TBO_seurat, features = c("ATOH1_Targets1"), pt.size=0.2,
            reduction='umap') + viridis::scale_color_viridis(option="rocket",direction=-1) & NoAxes()

FeaturePlot(TBO_seurat, features = c("POU2F3_Targets1"), pt.size=0.2,
            reduction='umap') + viridis::scale_color_viridis(option="rocket",direction=-1) & NoAxes()

FeaturePlot(TBO_seurat, features = c("YAP_Activity1"), pt.size=0.2,
            reduction='umap') + viridis::scale_color_viridis(option="rocket",direction=-1) & NoAxes()

VlnPlots by genotype with wilcoxon rank sum tests

Fig. 2j (violin plots)

plotTFscoresVln <- function(score_name, yl=c(-.1, .32)) {
    a <- VlnPlot(TBO_seurat,
                 features = c(score_name),
                 group.by = "Genotype",
                 cols = c("darkorchid4", "orange"),
                 pt.size = 0.01,
                 alpha = 0.05,
                 ncol = 1) + 
        theme(axis.title.y = element_text(size = 20),
              axis.text.x = element_text(angle = 0, hjust = 0.5, size=20),  # rotate x-axis labels
              # plot.title = element_blank(),                                 # remove plot title
              legend.position = "none"                                      # remove legend
        ) + 
        labs(x = "",             # custom x-axis title
             y = "Expression"  # custom y-axis title
        ) + ylim(yl[1], yl[2]) + 
        stat_summary(fun = mean,
                     geom = "point",
                     shape = 18,
                     size = 2,
                     color = "red",
                     position = position_dodge(width = 0.9)) + 
        ggpubr::stat_compare_means(method = "wilcox.test", label = "p.signif", size=8, 
                                   hide.ns = TRUE, comparisons = list(c("RPM", "RPMA")))
        
        # Add mean point and do wilcoxon rank sum test 
    return(a)
}

Fig 2j (insets)

plotTFscoresVln("ATOH1_Targets1")

plotTFscoresVln("ASCL1_Targets1", yl=c(-0.1, 0.8))

plotTFscoresVln("NEUROD1_Targets1")

plotTFscoresVln("POU2F3_Targets1")

plotTFscoresVln("YAP_Activity1", yl=c(-0.1, 1))

Fig. 2k (UMAP by cell type consensus signature)

FeaturePlot(TBO_seurat, features = c("NE_Consensus1"), pt.size=0.2, 
            reduction='umap') + viridis::scale_color_viridis(option="rocket",direction=-1) & NoAxes()

FeaturePlot(TBO_seurat, features = c("Basal_Consensus1"), pt.size=0.2,
            reduction='umap') + viridis::scale_color_viridis(option="rocket",direction=-1) & NoAxes()

FeaturePlot(TBO_seurat, features = c("Tuft_Consensus1"), pt.size=0.2,
            reduction='umap') + viridis::scale_color_viridis(option="rocket",direction=-1) & NoAxes()

Fig. 2k (violin plots of consensus signatures by SCLC fate)

plotVlnByPhen("NE_Consensus1", yl=c(-0.5, 1.3))

plotVlnByPhen("Tuft_Consensus1", yl=c(-0.25, 1))

plotVlnByPhen("Basal_Consensus1", yl=c(-0.1, 1.1))

Fig 2l (violin plots of SCLC arhcetype scores by phenotype)

plotVlnByPhen("A_Archetype1", yl=c(-0.05, 0.27))

plotVlnByPhen("A2_Archetype1", yl=c(-0.05, 0.2))

plotVlnByPhen("N_Archetype1", yl=c(0, 0.3))

plotVlnByPhen("P_Archetype1", yl=c(0, 0.27))

Ext Data Fig 5c

plotStackedBarByGeno <- function(gene, lab) {
    dat <- FetchData(TBO_seurat, vars = c(gene, "Genotype"))
    dat <- dat %>%
      mutate(Expression_Status = ifelse(dat[,gene] > 0.01, "Positive", "Negative"))
    
    x <- table(dat$Genotype, dat$Expression_Status)
    
    proportions <- as.data.frame(prop.table(x, margin = 1))
    colnames(proportions) <- c("Cluster", "Sample", "Fraction")

    p <- ggplot(proportions, aes(fill = Sample, y = Fraction, x = Cluster)) + 
        geom_bar(position = "stack", stat = "identity")
    p <- p + scale_fill_manual(values=c("blue4","red3"))+ theme_bw() + 
        theme(axis.text.y = element_text(size=20), axis.text.x=element_text(size=20), 
              axis.title.x =element_text(size=20), axis.title.y = element_text(size=20), 
              legend.text = element_text(size=20), legend.title = element_text(size=0), 
              plot.title = element_text(size = 18, face = "plain", hjust = 0.5)) + 
        labs(y = lab, x = NULL)
    return(p)
}
plotStackedBarByGeno("Ascl1", "Fraction of Ascl1-hi cells (>0.01)")

plotStackedBarByGeno("Neurod1", "Fraction of Neurod1-hi cells (>0.01)")

plotStackedBarByGeno("Pou2f3", "Fraction of Pou2f3-hi cells (>0.01)")

Extended Data Fig. 5e

Violin plots of expression of TFs by Leiden cluster

genes <- c("Ascl1","Neurod1","Pou2f3")

# Create violin plots with Kruskal-Wallis test
plots <- lapply(genes, function(gene) {
  p <- VlnPlot(TBO_seurat,
               features = gene,
               group.by = "leiden_scVI_1.2",
               cols = my_colors,
               alpha = 0.5) +  # smaller dots
    ggpubr::stat_compare_means(method = "kruskal.test", 
                       label = "p.format", 
                       label.x = 2,size = 5) +
    ggtitle("") +
    theme(plot.title = element_text(face = "italic"), legend.position = "none",  # Remove legend
          axis.title.x = element_blank(),axis.title.y = element_text(size = 20),
          axis.text.y = element_text(size = 20), axis.text.x = element_text(size = 14)) +  # Remove x-axis label
    labs(y = "Expression")  # Change y-axis label to "Expression"
  return(p)
})

# Arrange plots
patchwork::wrap_plots(plots, ncol = 3)

Ext Data Fig 10

FeaturePlot(TBO_seurat, features = c("Iono_Mouse_Ext1"), pt.size=0.2,
            reduction='umap') + viridis::scale_color_viridis(option="rocket",direction=-1) & NoAxes()

FeaturePlot(TBO_seurat, features = c("Iono_Human1"), pt.size=0.2,
            reduction='umap') + viridis::scale_color_viridis(option="rocket",direction=-1) & NoAxes()

Ext Data Fig. 10e (violin plots of consensus signatures by SCLC fate)

plotVlnByPhen("Iono_Mouse_Ext1", yl=c(-0.1, 0.45))

plotVlnByPhen("Iono_Human1", yl=c(-0.1, .75))

Fig 5d

Caris SCLC tumor signatures in basal cells

caris_feat <-  c("Caris_A1","Caris_Y1","Caris_N1","Caris_Mixed1","Caris_P1","Caris_TN-1")

v <- FeaturePlot(TBO_seurat, features = caris_feat, pt.size=0.2, reduction='umap') 
v <- lapply(v, `+`, scale_color_viridis(option="rocket", direction=-1))
lapply(v, `+`, NoAxes())
[[1]]

[[2]]

[[3]]

[[4]]

[[5]]

[[6]]

Fig 5d (violin plots of human tumor SCLC scores by SCLC fate)

plotVlnByPhen("Caris_A1", yl=c(-0.1, 0.2))

plotVlnByPhen("Caris_Y1", yl=c(-0.1, 0.2))

plotVlnByPhen("Caris_N1", yl=c(-0.1, 0.3))

plotVlnByPhen("Caris_Mixed1", yl=c(-0.1, 0.15))

plotVlnByPhen("Caris_P1", yl=c(-0.1, 0.25))

plotVlnByPhen("Caris_TN.1", yl=c(-0.1, 0.25))

Fig. 5e

Gene signature scores correlation heatmap

signature_matrix <- FetchData(TBO_seurat, vars = c("Caris_A1", "George_A1", "Liu_A1","Lissa_A1","ASCL1_Targets1",
                                                   "Caris_N1","George_N1", "Liu_N1","Lissa_N1", "NEUROD1_Targets1",
                                                   "Caris_P1","George_P1", "Liu_P1","POU2F3_Targets1",
                                                   "Caris_Y1","George_Y1", "Lissa_Y1", "YAP_Activity1",
                                                   "Gay_SCLC-I1","MHC_Sig_Gay1",
                                                   "NE_Consensus1","Basal_Consensus1","Tuft_Consensus1"))

# T_Cell_Inflamed_Gay1
# Compute Pearson correlation matrix
correlation_matrix <- cor(signature_matrix, method = "pearson")

# Define color scale from -1 to 1
breaks_seq <- seq(-1, 1, length.out = 100)  # Ensure scale covers full correlation range

pheatmap::pheatmap(correlation_matrix, 
         color = scico::scico(100, palette = "berlin"),
         display_numbers = FALSE, 
         breaks = breaks_seq, number_color = "gray80",fontsize_number=6,
         main = "Signature correlation in mouse TBO Allografts", cluster_cols = TRUE, cluster_rows=TRUE)

Fig 5g

Inflammatory signatures in basal cells

# Fig 5g feature plot (MHC_Sig_Gay1="Antigen presentation") #
FeaturePlot(TBO_seurat, features = c("MHC_Sig_Gay1"), pt.size=0.2, 
            reduction='umap') + viridis::scale_color_viridis(option="rocket",direction=-1) & NoAxes()


### NMF3-I signature for Fig. 5g
FeaturePlot(TBO_seurat, features = c("NMF3-I1"), pt.size=0.2, 
            reduction='umap') + viridis::scale_color_viridis(option="rocket",direction=-1) & NoAxes()


### Gay et al SCLC-I signature for Fig. 5g
FeaturePlot(TBO_seurat, features = c("Gay_SCLC-I1"), pt.size=0.2, 
            reduction='umap') + viridis::scale_color_viridis(option="rocket",direction=-1) & NoAxes()

Fig 5g (violin plots of inflammation scores by SCLC fate)

plotVlnByPhen("MHC_Sig_Gay1", yl=c(-0.1, 0.8))

plotVlnByPhen("NMF3.I1", yl=c(-0.1, 0.5))

plotVlnByPhen("Gay_SCLC.I1", yl=c(-0.1, 0.3))

Fig 5h (violin plots of therapeutic target gene expression by SCLC fate)

x_labs <- c("A","A/N","N","At","P","SL","B")

v <- VlnPlot(TBO_seurat, features = c("Dll3", "Ncam1", "Sez6", "Tacstd2"), 
        group.by=c("Pheno"), cols=pheno_col,alpha=0.05, ncol=4)
v <- lapply(v,  `+`, labs(x=NULL, y="Expression"))
v <- lapply(v,  `+`, theme(axis.text.x = element_text(angle=90)))
v <- lapply(v,  `+`,  scale_x_discrete(labels=x_labs))

patchwork::wrap_plots(v, ncol=4)

Ext Data Fig 6a

DimPlot(TBO_seurat, group.by='GenoCT', cols=my_colors, shuffle=TRUE, 
        reduction='umap', label=FALSE, label.size=6) & NoAxes() + NoLegend()

DimPlot(TBO_seurat, group.by='GenoCT', cols=my_colors, shuffle=TRUE, 
        reduction='fa', label=FALSE, label.size=6) & NoAxes() + NoLegend()

CellTag analysis in other notebook

LS0tCnRpdGxlOiAiUlBNIFJQTUEgQWxsb3Mgbm90ZWJvb2siCmF1dGhvcjogIkFiYmllIElyZWxhbmQsIERhcnJlbiBUeXNvbiIKZGF0ZTogIjIwMjUtMDYtMjQiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMjIyBNb2RpZnlpbmcgb3JpZ2luYWwgY29kZQpPcmlnaW5hbCBmaWxlOiBgRmlnM180XzZfRXh0RmlnNS02LTEwX1JQTV9SUE1BX0FsbG9zX0NlbGxUYWcuUmAgCltGaWczXzRfNl9FeHRGaWc1LTYtMTBfUlBNX1JQTUFfQWxsb3NfQ2VsbFRhZy5SIGZpbGUgb24gR2l0SHViXShodHRwczovL2dpdGh1Yi5jb20vVEdPbGl2ZXItbGFiL0lyZWxhbmRfQmFzYWxfU0NMQ18yMDI1L2Jsb2IvbWFpbi9SX0NvZGUvRmlnM180XzZfRXh0RmlnNS02LTEwX1JQTV9SUE1BX0FsbG9zX0NlbGxUYWcuUikgIAoKVGhpcyBub3RlYm9vayBpcyBtb2RpZmllZCBmcm9tIHRoZSBvcmlnaW5hbCBjb2RlIHRvIHJlbW92ZSB0aGUgcHJlcHJvY2Vzc2luZyBzdGVwcyAKYW5kIHNob3cgZmlndXJlcyBpbmxpbmUgd2l0aGluIHRoZSBub3RlYm9vay4gICAgCgpUaGVyZSBpcyBhIHNlcGFyYXRlIG5vdGVib29rIGZvciB0aGUgQ2VsbFRhZyBhbmFseXNpcy4KCiMjIyBSZWxhdGVkIHRvOgoqIEZpZyAyZS1sCiogRmlnIDVkLWgKKiBFeHRlbmRlZCBEYXRhIEZpZyA1YyxlCiogRXh0ZW5kZWQgRGF0YSBGaWcgNmEKKiBFeHRlbmRlZCBEYXRhIEZpZyAxMGUKCmBgYHtyfQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMoewogICAgbGlicmFyeShTZXVyYXQpCiAgICBsaWJyYXJ5KFNldXJhdE9iamVjdCkKICAgIGxpYnJhcnkoU3VtbWFyaXplZEV4cGVyaW1lbnQpCiAgICBsaWJyYXJ5KGdncGxvdDIpCiAgICBsaWJyYXJ5KGdncHVicikKfSkKYGBgCgojIyMgTG9hZCB0aGUgU2V1cmF0IG9iamVjdCBhbmQgQ2VsbFRhZyBjbG9uZXMKYGBge3J9ClRCT19zZXVyYXQ8LXJlYWRSRFMoIi4uL2RhdGEvMDVfMjAyNV9SUE1fUlBNQV9UQk9fQ2VsbFRhZ19TZXVyYXRfd1NpZ3NfRkFfZHB0X2ZpbmFsLnJkcyIpClRCT19zZXVyYXQKCmNsb25lcyA8LSByZWFkUkRTKCIuLi9kYXRhLzA1XzIwMjVfUlBNX1JQTUFfVEJPQWxsb19DZWxsVGFnQ2xvbmVzX09ubHljbG9uZXMucmRzIikKY2xvbmVzCmBgYAojIyMgTG9hZCBvcmdhbm9pZCBkYXRhIGFzIFNpbmdsZUNlbGxFeHBlcmltZW50CmBgYHtyfQpzY2UgPC0gYXMuU2luZ2xlQ2VsbEV4cGVyaW1lbnQoVEJPX3NldXJhdCwgYXNzYXkgPSAibm9ybSIpCmBgYAoKYGBge3J9CnBoZW5vdHlwZXMgPC0gYXMuY2hhcmFjdGVyKHVuaXF1ZShzY2VAY29sRGF0YUBsaXN0RGF0YSRQaGVubykpCnBoZW5vX3BhaXJzX2xpc3QgPC0gY29tYm4ocGhlbm90eXBlcywgMiwgc2ltcGxpZnkgPSBGQUxTRSkKYGBgCgoKIyMjIERlZmluZSBjb2xvciBwYWxldHRlcwpgYGB7cn0KbXlfY29sb3JzIDwtIGMoCiAgIiNFNDFBMUMiLCAjIHN0cm9uZyByZWQKICAiIzM3N0VCOCIsICMgbWVkaXVtIGJsdWUKICAiIzREQUY0QSIsICMgZ3JlZW4KICAiIzk4NEVBMyIsICMgcHVycGxlCiAgIiNGRjdGMDAiLCAjIG9yYW5nZQogICIjRkZGRjMzIiwgIyB5ZWxsb3cKICAiI0E2NTYyOCIsICMgYnJvd24KICAiI2U3Mjk4YSIsICMgcGluawogICIjNjY2NjY2IiwgIyBncmV5CiAgIiM2NkMyQTUiLCAjIHRlYWwKICAiI0ZDOEQ2MiIsICMgc2FsbW9uCiAgIiM4REEwQ0IiLCAjIHNvZnQgYmx1ZQogICIjRTc4QUMzIiwgIyBzb2Z0IHBpbmsgKGRpZmZlcmVudCBmcm9tIDgpCiAgIiNBNkQ4NTQiLCAjIGxpZ2h0IGdyZWVuIChidXQgeWVsbG93aXNoIHRpbnQsIG5vdCBncmVlbikKICAiI0ZGRDkyRiIsICMgbGVtb24geWVsbG93CiAgIiNFNUM0OTQiLCAjIGxpZ2h0IGJyb3duCiAgIiNCM0IzQjMiLCAjIGxpZ2h0IGdyZXkKICAiIzFCOUU3NyIsICMgZGVlcCB0ZWFsCiAgIiNEOTVGMDIiLCAjIGRhcmsgb3JhbmdlCiAgIiM3NTcwQjMiLCAjIHN0cm9uZyBwdXJwbGUKICAiIzY2QTYxRSIgICMgb2xpdmUgZ3JlZW4gKE5PVCBzYW1lIGdyZWVuIGFzIGJlZm9yZSkKKQoKYGBgCiMjIyMgRGVmaW5lIGZ1bmN0aW9uIHRvIHBsb3QgdmlvbGluIHBsb3RzIGJ5IHBoZW5vdHlwZQpDb3BpZWQgZnJvbSBbMDJfV1RfUlBNX09yZ2Fub2lkc19BbGxvZ3JhZnRzX25vdGVib29rLlJtZF0oMDJfV1RfUlBNX09yZ2Fub2lkc19BbGxvZ3JhZnRzX25vdGVib29rLlJtZCkgIAoKTmVlZHMgU2luZ2xlQ2VsbEV4cGVyaW1lbnQgYHNjZWAgb2JqZWN0IGFuZCBgcGhlbm9fcGFpcnNfbGlzdGAgZGVmaW5lZCBpbiB0aGUgbm90ZWJvb2suCmBgYHtyfQpwbG90VmxuQnlQaGVuIDwtIGZ1bmN0aW9uKGZlYXR1cmUsIHlsPWMoLTAuMSwwLjMpLCBmb2N1cz1OQSkgewogICAgaWYoIWlzLm5hKGZvY3VzKSkgewogICAgICAgIHBoZW5vX3BhaXJzX2xpc3QgPC0gcGhlbm9fcGFpcnNfbGlzdFtzYXBwbHkocGhlbm9fcGFpcnNfbGlzdCwgZnVuY3Rpb24oeCkgZm9jdXMgJWluJSB4KV0KICAgIH0KICAgIAogICAgc2NhdGVyOjpwbG90Q29sRGF0YShzY2UsIHggPSAiUGhlbm8iLCB5ID0gZmVhdHVyZSwgY29sb3VyX2J5ID0gIlBoZW5vIikgKyAKICAgICAgICBzY2FsZV9kaXNjcmV0ZV9tYW51YWwoYWVzdGhldGljcyA9IGMoImNvbG91ciIsICJmaWxsIiksIHZhbHVlcz1waGVub19jb2wpICsKICAgICAgICB0aGVtZShheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDI0KSwgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwKICAgICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwgICAjIHJvdGF0ZSB4LWF4aXMgbGFiZWxzCiAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgICAgIyByZW1vdmUgcGxvdCB0aXRsZQogICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiAgICAgICAgICMgcmVtb3ZlIGxlZ2VuZAogICAgICAgICkgKyBsYWJzKHggPSAiIiwgICAgICAgICAgICAgICAgICAgICAjIGN1c3RvbSB4LWF4aXMgdGl0bGUKICAgICAgICAgICAgICAgICB5ID0gIlNpZ25hdHVyZSBzY29yZSIgICAgICAgICMgY3VzdG9tIHktYXhpcyB0aXRsZQogICAgICAgICkgKyB5bGltKHlsWzFdLCB5bFsyXSkgKyAKICAgICAgICBnZW9tX2JveHBsb3QoZmlsbD1waGVub19jb2wsIGFscGhhPTEvNSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IC4yKSwKICAgICAgICAgICAgICAgICAgICAgc2l6ZT0wLjIsIGNvbG9yPSJibGFjayIsIG5vdGNoPVRSVUUsIG5vdGNod2lkdGg9MC4zLCBvdXRsaWVyLnNoYXBlID0gMiwgb3V0bGllci5jb2xvdXI9TkEpICMgKyAKICAgICAgICAjIHN0YXRfc3VtbWFyeShmdW4gPSBtZWFuLAogICAgICAgICMgICAgICAgICAgICAgIGdlb20gPSAicG9pbnQiLAogICAgICAgICMgICAgICAgICAgICAgIHNoYXBlID0gMTgsCiAgICAgICAgIyAgICAgICAgICAgICAgc2l6ZSA9IDIsCiAgICAgICAgIyAgICAgICAgICAgICAgY29sb3IgPSAicmVkIiwKICAgICAgICAjICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC41KSkgKyAKICAgICAgICAjIGdncHVicjo6c3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ3aWxjb3gudGVzdCIsIGxhYmVsID0gInAuc2lnbmlmIiwgc2l6ZT00LCAKICAgICAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0ID0gMC41LAogICAgICAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGlkZS5ucyA9IFRSVUUsIGNvbXBhcmlzb25zID0gcGhlbm9fcGFpcnNfbGlzdCkKfQpgYGAKCiMjIyBGaWcuIDJlIFVNQVAKYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9NywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KRGltUGxvdChUQk9fc2V1cmF0LCBncm91cC5ieT0nR2Vub3R5cGUnLCBjb2xzPWMoImRhcmtvcmNoaWQ0Iiwib3JhbmdlIiksCiAgICAgICAgcHQuc2l6ZSA9IDAuMSwKICAgICAgICByZWR1Y3Rpb249J3VtYXAnLCBsYWJlbD1GQUxTRSwgbGFiZWwuc2l6ZT03LCBzaHVmZmxlPVRSVUUpICYgTm9BeGVzKCkKCmBgYAoKIyMjIEZpZy4gMmYgKFVNQVAgYnkgTGVpZGVuIGNsdXN0ZXIpCmBgYHtyIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTYsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CkRpbVBsb3QoVEJPX3NldXJhdCwgZ3JvdXAuYnk9J2xlaWRlbl9zY1ZJXzEuMicsIAogICAgICAgIGNvbHM9bXlfY29sb3JzLCByZWR1Y3Rpb249J3VtYXAnLCBsYWJlbD1UUlVFLCBsYWJlbC5zaXplPTUsCiAgICAgICAgcHQuc2l6ZSA9IDAuMSkgJiBOb0F4ZXMoKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKQoKYGBgCgoKYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CklkZW50cyhUQk9fc2V1cmF0KSA8LSAnbGVpZGVuX3NjVklfMS4yJwoKeCA8LSB0YWJsZShUQk9fc2V1cmF0QG1ldGEuZGF0YSRHZW5vdHlwZSxJZGVudHMoVEJPX3NldXJhdCkpCnByb3BvcnRpb25zIDwtIGFzLmRhdGEuZnJhbWUoMTAwKnByb3AudGFibGUoeCwgbWFyZ2luID0gMSkpCgpjb2xuYW1lcyhwcm9wb3J0aW9ucykgPC0gYygiU2FtcGxlIiwgIkNsdXN0ZXIiLCAiRnJlcXVlbmN5IikKCiMgZ2dwdWJyOjpnZ2JhcnBsb3QocHJvcG9ydGlvbnMsIHg9IlNhbXBsZSIsIHk9IkZyZXF1ZW5jeSIsIGZpbGwgPSAiU2FtcGxlIiwgZ3JvdXAgPSAiU2FtcGxlIiwKIyAgICAgICAgICAgICAgICAgICB5bGFiID0gIkZyZXF1ZW5jeSAocGVyY2VudCkiLCB4bGFiPSJQaGFzZSIsIHBhbGV0dGUgPWMoImluZGlhbnJlZDMiLCJncmVlbjMiLCJyb3lhbGJsdWU0IikpICsKIyAgICAgdGhlbWVfYncoKSArIGZhY2V0X3dyYXAoZmFjZXRzID0gIkNsdXN0ZXIiLCBzY2FsZXM9ImZyZWVfeSIsIG5jb2wgPTQpICsKIyAgICAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZT02KSkgKyBnZ3B1YnI6OnJvdGF0ZV94X3RleHQoYW5nbGUgPSA0NSkKYGBgCgojIyMjIEZpZyAyZgpgYGB7ciBmaWcuaGVpZ2h0PTMuNSwgZmlnLndpZHRoPTMuNSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBTdGFja2VkCnAgPC0gZ2dwbG90KHByb3BvcnRpb25zLCBhZXMoZmlsbD1DbHVzdGVyLCB5PUZyZXF1ZW5jeSwgeD1TYW1wbGUpKSArIAogICAgZ2VvbV9iYXIocG9zaXRpb249InN0YWNrIiwgc3RhdD0iaWRlbnRpdHkiKQoKcCArIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1teV9jb2xvcnMpICsgdGhlbWVfYncoKSArIAogICAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZT0xNiksIAogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0xNiwgYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpLCAKICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplPTE2KSwgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemU9MTYpLCAKICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTIpLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgICBsYWJzKHggPSBOVUxMLCB5ID0gIlNhbXBsZSBjb21wb3NpdGlvbiAoJSkiKQpgYGAKCiMjIyBGaWcuIDJoIApVTUFQIGNvbG9yZWQgYnkgU0NMQyBmYXRlCmBgYHtyIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTcsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgRGVmaW5lIGZhdGUgY29sb3IgdmVjdG9yIGFuZCB1c2UgdG8gcGxvdCBieSBjZWxsIHN0YXRlCnBoZW5vX2NvbCA8LSBjKCJicm93bjIiLCJkYXJrb3JjaGlkNCIsImRvZGdlcmJsdWUiLCIjNjZBNjFFIiwib3JhbmdlIiwidHVycXVvaXNlNCIsInR1cnF1b2lzZSIpCkRpbVBsb3QoVEJPX3NldXJhdCwgZ3JvdXAuYnk9J1BoZW5vJywgY29scz1waGVub19jb2wsIHJlZHVjdGlvbj0ndW1hcCcsIGxhYmVsPUZBTFNFLCAKICAgICAgICBzaHVmZmxlPVRSVUUsIGxhYmVsLnNpemU9NikgJiBOb0F4ZXMoKQoKYGBgCiMjIyMgRmlnLiAyaCAoc3RhY2tlZCBiYXJwbG90IGJ5IFBoZW5vKQoKYGBge3IgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9NCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KSWRlbnRzKFRCT19zZXVyYXQpIDwtJ1BoZW5vJwoKeCA8LSB0YWJsZShUQk9fc2V1cmF0QG1ldGEuZGF0YSRHZW5vdHlwZSxJZGVudHMoVEJPX3NldXJhdCkpCnByb3BvcnRpb25zIDwtIGFzLmRhdGEuZnJhbWUoMTAwKnByb3AudGFibGUoeCwgbWFyZ2luID0gMSkpCgpjb2xuYW1lcyhwcm9wb3J0aW9ucyk8LWMoIkNsdXN0ZXIiLCAiU2FtcGxlIiwgIkZyZXF1ZW5jeSIpCgpwIDwtIGdncGxvdChwcm9wb3J0aW9ucywgYWVzKGZpbGw9U2FtcGxlLCB5PUZyZXF1ZW5jeSwgeD1DbHVzdGVyKSkgKyAKICAgIGdlb21fYmFyKHBvc2l0aW9uPSJzdGFjayIsIHN0YXQ9ImlkZW50aXR5IikKCnAgKyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9cGhlbm9fY29sKSArIHRoZW1lX2J3KCkgKyAKICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemU9MjApLCAKICAgICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChzaXplPTIwLCBhbmdsZSA9IDkwLCBoanVzdCA9IDEsIHZqdXN0ID0gMC41KSwgCiAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZT0yMCksIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSwgCiAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MjApKSArIAogICAgbGFicyh4ID0gTlVMTCkKYGBgCgojIyMjIEZpZy4gMmkgVU1BUApORSBzY29yZSAoY29ycmVsYXRpb24pCmBgYHtyIGZpZy5oZWlnaHQ9MywgZmlnLndpZHRoPTMuNSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KRmVhdHVyZVBsb3QoVEJPX3NldXJhdCwgZmVhdHVyZXMgPSBjKCJORV9zcGVhcm1hbiIpLCBwdC5zaXplPTAuMiwKICAgICAgICAgICAgcmVkdWN0aW9uPSd1bWFwJykgKyB2aXJpZGlzOjpzY2FsZV9jb2xvcl92aXJpZGlzKG9wdGlvbj0icm9ja2V0IixkaXJlY3Rpb249LTEpICYgTm9BeGVzKCkKYGBgCgojIyMjIEZpZyAyaSAodmlvbGluIHBsb3RzIG9mIE5FIHNjb3JlIGJ5IFNDTEMgZmF0ZSkKYGBge3IgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9MywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcGxvdFZsbkJ5UGhlbigiTkVfc3BlYXJtYW4iLCB5bD1jKC0uNywgLjgpKQpgYGAKCiMjIyMgRmlnIDJpICh2aW9saW4gcGxvdHMgb2YgTkUgc2NvcmUgYnkgZ2Vub3R5cGUpCmBgYHtyIGZpZy5oZWlnaHQ9MywgZmlnLndpZHRoPTIsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnggPC0gc2NhdGVyOjpwbG90Q29sRGF0YShzY2UsIHggPSAiR2Vub3R5cGUiLCB5ID0gIk5FX3NwZWFybWFuIiwgY29sb3VyX2J5ID0gIkdlbm90eXBlIikgKyAKICAgIHNjYWxlX2Rpc2NyZXRlX21hbnVhbChhZXN0aGV0aWNzID0gYygiY29sb3VyIiwgImZpbGwiKSwgdmFsdWVzPWMoImRhcmtvcmNoaWQ0Iiwib3JhbmdlIikpCgp4IDwtIHggKyB0aGVtZShheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDI0KSxheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpLCAKICAgICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgICAjIHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKyBsYWJzKHggPSAiIiwgIHkgPSAiU2lnbmF0dXJlIHNjb3JlIikgKyAgeWxpbSgtMSwxKSArIAogICAgZ2VvbV9ib3hwbG90KGZpbGw9YygiZGFya29yY2hpZDQiLCJvcmFuZ2UiKSwgYWxwaGE9MS81LCAKICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gLjIpLCBzaXplPTAuMiwKICAgICAgICAgICAgICAgICBjb2xvcj0iYmxhY2siLCBub3RjaD1UUlVFLCBub3RjaHdpZHRoPTAuMywgb3V0bGllci5zaGFwZSA9IDIsIG91dGxpZXIuY29sb3VyPU5BKQoKIyMgUGVyZm9ybSB3aWxjb3hvbiByYW5rLXN1bSB0ZXN0IGZvciBSUE0gdnMgUlBNQSBvbiB0aGUgTkUgc2NvcmUgZGF0YSAoRmlnLiAzaSkgIyMKeCArIHN0YXRfc3VtbWFyeShmdW4gPSBtZWFuLAogICAgICAgICAgICAgICAgIGdlb20gPSAicG9pbnQiLAogICAgICAgICAgICAgICAgIHNoYXBlID0gMTgsCiAgICAgICAgICAgICAgICAgc2l6ZSA9IDIsCiAgICAgICAgICAgICAgICAgY29sb3IgPSAicmVkIiwKICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSkgKyAKICAgIGdncHVicjo6c3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ3aWxjb3gudGVzdCIsbGFiZWwgPSAicC5zaWduaWYiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhpZGUubnMgPSBUUlVFLGNvbXBhcmlzb25zID0gbGlzdChjKCJSUE0iLCAiUlBNQSIpKSkKCmBgYAoKCiMjIyBGaWcuIDJqIAojIyMjIEZpZyAyaiAoVU1BUCBtYXJrZXIgZ2VuZSBleHByZXNzaW9uKQpFcXVpdmFsZW50IGNvbG9yIHNjaGVtZXM6ICAKKiBgdmlyaWRpczo6c2NhbGVfY29sb3JfdmlyaWRpcyhvcHRpb249InJvY2tldCIsIGRpcmVjdGlvbj0tMSlgICAKKiBgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycz12aXJpZGlzOjpyb2NrZXQoMTAsIGRpcmVjdGlvbj0tMSkpYAoKCmBgYHtyIGZpZy5oZWlnaHQ9MywgZmlnLndpZHRoPTQsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgVEYgdGFyZ2V0IGdlbmUgc2NvcmVzIGluIFVNQVAKRmVhdHVyZVBsb3QoVEJPX3NldXJhdCwgZmVhdHVyZXMgPSBjKCJBU0NMMV9UYXJnZXRzMSIpLCBwdC5zaXplPTAuMiwgCiAgICAgICAgICAgIHJlZHVjdGlvbj0ndW1hcCcpICsgdmlyaWRpczo6c2NhbGVfY29sb3JfdmlyaWRpcyhvcHRpb249InJvY2tldCIsZGlyZWN0aW9uPS0xKSAmIE5vQXhlcygpCkZlYXR1cmVQbG90KFRCT19zZXVyYXQsIGZlYXR1cmVzID0gYygiTkVVUk9EMV9UYXJnZXRzMSIpLCBwdC5zaXplPTAuMiwKICAgICAgICAgICAgcmVkdWN0aW9uPSd1bWFwJykgKyB2aXJpZGlzOjpzY2FsZV9jb2xvcl92aXJpZGlzKG9wdGlvbj0icm9ja2V0IixkaXJlY3Rpb249LTEpICYgTm9BeGVzKCkKRmVhdHVyZVBsb3QoVEJPX3NldXJhdCwgZmVhdHVyZXMgPSBjKCJBVE9IMV9UYXJnZXRzMSIpLCBwdC5zaXplPTAuMiwKICAgICAgICAgICAgcmVkdWN0aW9uPSd1bWFwJykgKyB2aXJpZGlzOjpzY2FsZV9jb2xvcl92aXJpZGlzKG9wdGlvbj0icm9ja2V0IixkaXJlY3Rpb249LTEpICYgTm9BeGVzKCkKRmVhdHVyZVBsb3QoVEJPX3NldXJhdCwgZmVhdHVyZXMgPSBjKCJQT1UyRjNfVGFyZ2V0czEiKSwgcHQuc2l6ZT0wLjIsCiAgICAgICAgICAgIHJlZHVjdGlvbj0ndW1hcCcpICsgdmlyaWRpczo6c2NhbGVfY29sb3JfdmlyaWRpcyhvcHRpb249InJvY2tldCIsZGlyZWN0aW9uPS0xKSAmIE5vQXhlcygpCkZlYXR1cmVQbG90KFRCT19zZXVyYXQsIGZlYXR1cmVzID0gYygiWUFQX0FjdGl2aXR5MSIpLCBwdC5zaXplPTAuMiwKICAgICAgICAgICAgcmVkdWN0aW9uPSd1bWFwJykgKyB2aXJpZGlzOjpzY2FsZV9jb2xvcl92aXJpZGlzKG9wdGlvbj0icm9ja2V0IixkaXJlY3Rpb249LTEpICYgTm9BeGVzKCkKCmBgYAoKCiMjIyBWbG5QbG90cyBieSBnZW5vdHlwZSB3aXRoIHdpbGNveG9uIHJhbmsgc3VtIHRlc3RzCiMjIyMgRmlnLiAyaiAodmlvbGluIHBsb3RzKQpgYGB7cn0KcGxvdFRGc2NvcmVzVmxuIDwtIGZ1bmN0aW9uKHNjb3JlX25hbWUsIHlsPWMoLS4xLCAuMzIpKSB7CiAgICBhIDwtIFZsblBsb3QoVEJPX3NldXJhdCwKICAgICAgICAgICAgICAgICBmZWF0dXJlcyA9IGMoc2NvcmVfbmFtZSksCiAgICAgICAgICAgICAgICAgZ3JvdXAuYnkgPSAiR2Vub3R5cGUiLAogICAgICAgICAgICAgICAgIGNvbHMgPSBjKCJkYXJrb3JjaGlkNCIsICJvcmFuZ2UiKSwKICAgICAgICAgICAgICAgICBwdC5zaXplID0gMC4wMSwKICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMDUsCiAgICAgICAgICAgICAgICAgbmNvbCA9IDEpICsgCiAgICAgICAgdGhlbWUoYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCksCiAgICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCBoanVzdCA9IDAuNSwgc2l6ZT0yMCksICAjIHJvdGF0ZSB4LWF4aXMgbGFiZWxzCiAgICAgICAgICAgICAgIyBwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgcmVtb3ZlIHBsb3QgdGl0bGUKICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgcmVtb3ZlIGxlZ2VuZAogICAgICAgICkgKyAKICAgICAgICBsYWJzKHggPSAiIiwgICAgICAgICAgICAgIyBjdXN0b20geC1heGlzIHRpdGxlCiAgICAgICAgICAgICB5ID0gIkV4cHJlc3Npb24iICAjIGN1c3RvbSB5LWF4aXMgdGl0bGUKICAgICAgICApICsgeWxpbSh5bFsxXSwgeWxbMl0pICsgCiAgICAgICAgc3RhdF9zdW1tYXJ5KGZ1biA9IG1lYW4sCiAgICAgICAgICAgICAgICAgICAgIGdlb20gPSAicG9pbnQiLAogICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDE4LAogICAgICAgICAgICAgICAgICAgICBzaXplID0gMiwKICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAicmVkIiwKICAgICAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOSkpICsgCiAgICAgICAgZ2dwdWJyOjpzdGF0X2NvbXBhcmVfbWVhbnMobWV0aG9kID0gIndpbGNveC50ZXN0IiwgbGFiZWwgPSAicC5zaWduaWYiLCBzaXplPTgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhpZGUubnMgPSBUUlVFLCBjb21wYXJpc29ucyA9IGxpc3QoYygiUlBNIiwgIlJQTUEiKSkpCiAgICAgICAgCiAgICAgICAgIyBBZGQgbWVhbiBwb2ludCBhbmQgZG8gd2lsY294b24gcmFuayBzdW0gdGVzdCAKICAgIHJldHVybihhKQp9CmBgYAojIyMjIEZpZyAyaiAoaW5zZXRzKQpgYGB7ciBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD0zLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwbG90VEZzY29yZXNWbG4oIkFUT0gxX1RhcmdldHMxIikKcGxvdFRGc2NvcmVzVmxuKCJBU0NMMV9UYXJnZXRzMSIsIHlsPWMoLTAuMSwgMC44KSkKcGxvdFRGc2NvcmVzVmxuKCJORVVST0QxX1RhcmdldHMxIikKcGxvdFRGc2NvcmVzVmxuKCJQT1UyRjNfVGFyZ2V0czEiKQpwbG90VEZzY29yZXNWbG4oIllBUF9BY3Rpdml0eTEiLCB5bD1jKC0wLjEsIDEpKQpgYGAKCiMjIyBGaWcuIDJrIChVTUFQIGJ5IGNlbGwgdHlwZSBjb25zZW5zdXMgc2lnbmF0dXJlKQpgYGB7ciBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD00LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpGZWF0dXJlUGxvdChUQk9fc2V1cmF0LCBmZWF0dXJlcyA9IGMoIk5FX0NvbnNlbnN1czEiKSwgcHQuc2l6ZT0wLjIsIAogICAgICAgICAgICByZWR1Y3Rpb249J3VtYXAnKSArIHZpcmlkaXM6OnNjYWxlX2NvbG9yX3ZpcmlkaXMob3B0aW9uPSJyb2NrZXQiLGRpcmVjdGlvbj0tMSkgJiBOb0F4ZXMoKQpGZWF0dXJlUGxvdChUQk9fc2V1cmF0LCBmZWF0dXJlcyA9IGMoIkJhc2FsX0NvbnNlbnN1czEiKSwgcHQuc2l6ZT0wLjIsCiAgICAgICAgICAgIHJlZHVjdGlvbj0ndW1hcCcpICsgdmlyaWRpczo6c2NhbGVfY29sb3JfdmlyaWRpcyhvcHRpb249InJvY2tldCIsZGlyZWN0aW9uPS0xKSAmIE5vQXhlcygpCkZlYXR1cmVQbG90KFRCT19zZXVyYXQsIGZlYXR1cmVzID0gYygiVHVmdF9Db25zZW5zdXMxIiksIHB0LnNpemU9MC4yLAogICAgICAgICAgICByZWR1Y3Rpb249J3VtYXAnKSArIHZpcmlkaXM6OnNjYWxlX2NvbG9yX3ZpcmlkaXMob3B0aW9uPSJyb2NrZXQiLGRpcmVjdGlvbj0tMSkgJiBOb0F4ZXMoKQpgYGAKCiMjIyBGaWcuIDJrICh2aW9saW4gcGxvdHMgb2YgY29uc2Vuc3VzIHNpZ25hdHVyZXMgYnkgU0NMQyBmYXRlKQpgYGB7ciBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD0zLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwbG90VmxuQnlQaGVuKCJORV9Db25zZW5zdXMxIiwgeWw9YygtMC41LCAxLjMpKQpwbG90VmxuQnlQaGVuKCJUdWZ0X0NvbnNlbnN1czEiLCB5bD1jKC0wLjI1LCAxKSkKcGxvdFZsbkJ5UGhlbigiQmFzYWxfQ29uc2Vuc3VzMSIsIHlsPWMoLTAuMSwgMS4xKSkKYGBgCiMjIyMgRmlnIDJsICh2aW9saW4gcGxvdHMgb2YgU0NMQyBhcmhjZXR5cGUgc2NvcmVzIGJ5IHBoZW5vdHlwZSkKYGBge3IgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9MywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcGxvdFZsbkJ5UGhlbigiQV9BcmNoZXR5cGUxIiwgeWw9YygtMC4wNSwgMC4yNykpCnBsb3RWbG5CeVBoZW4oIkEyX0FyY2hldHlwZTEiLCB5bD1jKC0wLjA1LCAwLjIpKQpwbG90VmxuQnlQaGVuKCJOX0FyY2hldHlwZTEiLCB5bD1jKDAsIDAuMykpCnBsb3RWbG5CeVBoZW4oIlBfQXJjaGV0eXBlMSIsIHlsPWMoMCwgMC4yNykpCmBgYAoKIyMjIyBFeHQgRGF0YSBGaWcgNWMKYGBge3J9CnBsb3RTdGFja2VkQmFyQnlHZW5vIDwtIGZ1bmN0aW9uKGdlbmUsIGxhYikgewogICAgZGF0IDwtIEZldGNoRGF0YShUQk9fc2V1cmF0LCB2YXJzID0gYyhnZW5lLCAiR2Vub3R5cGUiKSkKICAgIGRhdCA8LSBkYXQgJT4lCiAgICAgIG11dGF0ZShFeHByZXNzaW9uX1N0YXR1cyA9IGlmZWxzZShkYXRbLGdlbmVdID4gMC4wMSwgIlBvc2l0aXZlIiwgIk5lZ2F0aXZlIikpCiAgICAKICAgIHggPC0gdGFibGUoZGF0JEdlbm90eXBlLCBkYXQkRXhwcmVzc2lvbl9TdGF0dXMpCiAgICAKICAgIHByb3BvcnRpb25zIDwtIGFzLmRhdGEuZnJhbWUocHJvcC50YWJsZSh4LCBtYXJnaW4gPSAxKSkKICAgIGNvbG5hbWVzKHByb3BvcnRpb25zKSA8LSBjKCJDbHVzdGVyIiwgIlNhbXBsZSIsICJGcmFjdGlvbiIpCgogICAgcCA8LSBnZ3Bsb3QocHJvcG9ydGlvbnMsIGFlcyhmaWxsID0gU2FtcGxlLCB5ID0gRnJhY3Rpb24sIHggPSBDbHVzdGVyKSkgKyAKICAgICAgICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIsIHN0YXQgPSAiaWRlbnRpdHkiKQogICAgcCA8LSBwICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoImJsdWU0IiwicmVkMyIpKSsgdGhlbWVfYncoKSArIAogICAgICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemU9MjApLCBheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT0yMCksIAogICAgICAgICAgICAgIGF4aXMudGl0bGUueCA9ZWxlbWVudF90ZXh0KHNpemU9MjApLCBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCksIAogICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MjApLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0wKSwgCiAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGZhY2UgPSAicGxhaW4iLCBoanVzdCA9IDAuNSkpICsgCiAgICAgICAgbGFicyh5ID0gbGFiLCB4ID0gTlVMTCkKICAgIHJldHVybihwKQp9CmBgYAoKYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9NiwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcGxvdFN0YWNrZWRCYXJCeUdlbm8oIkFzY2wxIiwgIkZyYWN0aW9uIG9mIEFzY2wxLWhpIGNlbGxzICg+MC4wMSkiKQpwbG90U3RhY2tlZEJhckJ5R2VubygiTmV1cm9kMSIsICJGcmFjdGlvbiBvZiBOZXVyb2QxLWhpIGNlbGxzICg+MC4wMSkiKQpwbG90U3RhY2tlZEJhckJ5R2VubygiUG91MmYzIiwgIkZyYWN0aW9uIG9mIFBvdTJmMy1oaSBjZWxscyAoPjAuMDEpIikKYGBgCgoKCiMjIyBFeHRlbmRlZCBEYXRhIEZpZy4gNWUKVmlvbGluIHBsb3RzIG9mIGV4cHJlc3Npb24gb2YgVEZzIGJ5IExlaWRlbiBjbHVzdGVyCmBgYHtyIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpnZW5lcyA8LSBjKCJBc2NsMSIsIk5ldXJvZDEiLCJQb3UyZjMiKQoKIyBDcmVhdGUgdmlvbGluIHBsb3RzIHdpdGggS3J1c2thbC1XYWxsaXMgdGVzdApwbG90cyA8LSBsYXBwbHkoZ2VuZXMsIGZ1bmN0aW9uKGdlbmUpIHsKICBwIDwtIFZsblBsb3QoVEJPX3NldXJhdCwKICAgICAgICAgICAgICAgZmVhdHVyZXMgPSBnZW5lLAogICAgICAgICAgICAgICBncm91cC5ieSA9ICJsZWlkZW5fc2NWSV8xLjIiLAogICAgICAgICAgICAgICBjb2xzID0gbXlfY29sb3JzLAogICAgICAgICAgICAgICBhbHBoYSA9IDAuNSkgKyAgIyBzbWFsbGVyIGRvdHMKICAgIGdncHVicjo6c3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJrcnVza2FsLnRlc3QiLCAKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICJwLmZvcm1hdCIsIAogICAgICAgICAgICAgICAgICAgICAgIGxhYmVsLnggPSAyLHNpemUgPSA1KSArCiAgICBnZ3RpdGxlKCIiKSArCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiaXRhbGljIiksIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgICMgUmVtb3ZlIGxlZ2VuZAogICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLAogICAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSkgKyAgIyBSZW1vdmUgeC1heGlzIGxhYmVsCiAgICBsYWJzKHkgPSAiRXhwcmVzc2lvbiIpICAjIENoYW5nZSB5LWF4aXMgbGFiZWwgdG8gIkV4cHJlc3Npb24iCiAgcmV0dXJuKHApCn0pCgojIEFycmFuZ2UgcGxvdHMKcGF0Y2h3b3JrOjp3cmFwX3Bsb3RzKHBsb3RzLCBuY29sID0gMykKYGBgCgoKIyMjIyBFeHQgRGF0YSBGaWcgMTAKYGBge3IgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9NCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KRmVhdHVyZVBsb3QoVEJPX3NldXJhdCwgZmVhdHVyZXMgPSBjKCJJb25vX01vdXNlX0V4dDEiKSwgcHQuc2l6ZT0wLjIsCiAgICAgICAgICAgIHJlZHVjdGlvbj0ndW1hcCcpICsgdmlyaWRpczo6c2NhbGVfY29sb3JfdmlyaWRpcyhvcHRpb249InJvY2tldCIsZGlyZWN0aW9uPS0xKSAmIE5vQXhlcygpCkZlYXR1cmVQbG90KFRCT19zZXVyYXQsIGZlYXR1cmVzID0gYygiSW9ub19IdW1hbjEiKSwgcHQuc2l6ZT0wLjIsCiAgICAgICAgICAgIHJlZHVjdGlvbj0ndW1hcCcpICsgdmlyaWRpczo6c2NhbGVfY29sb3JfdmlyaWRpcyhvcHRpb249InJvY2tldCIsZGlyZWN0aW9uPS0xKSAmIE5vQXhlcygpCmBgYAoKCiMjIyBFeHQgRGF0YSBGaWcuIDEwZSAodmlvbGluIHBsb3RzIG9mIGNvbnNlbnN1cyBzaWduYXR1cmVzIGJ5IFNDTEMgZmF0ZSkKYGBge3IgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9MywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcGxvdFZsbkJ5UGhlbigiSW9ub19Nb3VzZV9FeHQxIiwgeWw9YygtMC4xLCAwLjQ1KSkKcGxvdFZsbkJ5UGhlbigiSW9ub19IdW1hbjEiLCB5bD1jKC0wLjEsIC43NSkpCmBgYAoKIyMjIyBGaWcgNWQKQ2FyaXMgU0NMQyB0dW1vciBzaWduYXR1cmVzIGluIGJhc2FsIGNlbGxzCmBgYHtyIGZpZy5oZWlnaHQ9MywgZmlnLndpZHRoPTQsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmNhcmlzX2ZlYXQgPC0gIGMoIkNhcmlzX0ExIiwiQ2FyaXNfWTEiLCJDYXJpc19OMSIsIkNhcmlzX01peGVkMSIsIkNhcmlzX1AxIiwiQ2FyaXNfVE4tMSIpCgp2IDwtIEZlYXR1cmVQbG90KFRCT19zZXVyYXQsIGZlYXR1cmVzID0gY2FyaXNfZmVhdCwgcHQuc2l6ZT0wLjIsIHJlZHVjdGlvbj0ndW1hcCcpIAp2IDwtIGxhcHBseSh2LCBgK2AsIHNjYWxlX2NvbG9yX3ZpcmlkaXMob3B0aW9uPSJyb2NrZXQiLCBkaXJlY3Rpb249LTEpKQpsYXBwbHkodiwgYCtgLCBOb0F4ZXMoKSkKYGBgCgoKIyMjIyBGaWcgNWQgKHZpb2xpbiBwbG90cyBvZiBodW1hbiB0dW1vciBTQ0xDIHNjb3JlcyBieSBTQ0xDIGZhdGUpCmBgYHtyIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTMuNSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcGxvdFZsbkJ5UGhlbigiQ2FyaXNfQTEiLCB5bD1jKC0wLjEsIDAuMikpCnBsb3RWbG5CeVBoZW4oIkNhcmlzX1kxIiwgeWw9YygtMC4xLCAwLjIpKQpwbG90VmxuQnlQaGVuKCJDYXJpc19OMSIsIHlsPWMoLTAuMSwgMC4zKSkKcGxvdFZsbkJ5UGhlbigiQ2FyaXNfTWl4ZWQxIiwgeWw9YygtMC4xLCAwLjE1KSkKcGxvdFZsbkJ5UGhlbigiQ2FyaXNfUDEiLCB5bD1jKC0wLjEsIDAuMjUpKQpwbG90VmxuQnlQaGVuKCJDYXJpc19UTi4xIiwgeWw9YygtMC4xLCAwLjI1KSkKYGBgCgoKCiMjIyMgRmlnLiA1ZQpHZW5lIHNpZ25hdHVyZSBzY29yZXMgY29ycmVsYXRpb24gaGVhdG1hcApgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD05fQpzaWduYXR1cmVfbWF0cml4IDwtIEZldGNoRGF0YShUQk9fc2V1cmF0LCB2YXJzID0gYygiQ2FyaXNfQTEiLCAiR2VvcmdlX0ExIiwgIkxpdV9BMSIsIkxpc3NhX0ExIiwiQVNDTDFfVGFyZ2V0czEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ2FyaXNfTjEiLCJHZW9yZ2VfTjEiLCAiTGl1X04xIiwiTGlzc2FfTjEiLCAiTkVVUk9EMV9UYXJnZXRzMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDYXJpc19QMSIsIkdlb3JnZV9QMSIsICJMaXVfUDEiLCJQT1UyRjNfVGFyZ2V0czEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ2FyaXNfWTEiLCJHZW9yZ2VfWTEiLCAiTGlzc2FfWTEiLCAiWUFQX0FjdGl2aXR5MSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHYXlfU0NMQy1JMSIsIk1IQ19TaWdfR2F5MSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJORV9Db25zZW5zdXMxIiwiQmFzYWxfQ29uc2Vuc3VzMSIsIlR1ZnRfQ29uc2Vuc3VzMSIpKQojIHJlcGxhY2UgR2F5X1NDTEMtSTEgd2l0aCBUX0NlbGxfSW5mbGFtZWRfR2F5MQoKIyBDb21wdXRlIFBlYXJzb24gY29ycmVsYXRpb24gbWF0cml4CmNvcnJlbGF0aW9uX21hdHJpeCA8LSBjb3Ioc2lnbmF0dXJlX21hdHJpeCwgbWV0aG9kID0gInBlYXJzb24iKQoKIyBEZWZpbmUgY29sb3Igc2NhbGUgZnJvbSAtMSB0byAxCmJyZWFrc19zZXEgPC0gc2VxKC0xLCAxLCBsZW5ndGgub3V0ID0gMTAwKSAgIyBFbnN1cmUgc2NhbGUgY292ZXJzIGZ1bGwgY29ycmVsYXRpb24gcmFuZ2UKCnBoZWF0bWFwOjpwaGVhdG1hcChjb3JyZWxhdGlvbl9tYXRyaXgsIAogICAgICAgICBjb2xvciA9IHNjaWNvOjpzY2ljbygxMDAsIHBhbGV0dGUgPSAiYmVybGluIiksCiAgICAgICAgIGRpc3BsYXlfbnVtYmVycyA9IEZBTFNFLCAKICAgICAgICAgYnJlYWtzID0gYnJlYWtzX3NlcSwgbnVtYmVyX2NvbG9yID0gImdyYXk4MCIsZm9udHNpemVfbnVtYmVyPTYsCiAgICAgICAgIG1haW4gPSAiU2lnbmF0dXJlIGNvcnJlbGF0aW9uIGluIG1vdXNlIFRCTyBBbGxvZ3JhZnRzIiwgY2x1c3Rlcl9jb2xzID0gVFJVRSwgY2x1c3Rlcl9yb3dzPVRSVUUpCmBgYAoKIyMjIyBGaWcgNWcKSW5mbGFtbWF0b3J5IHNpZ25hdHVyZXMgaW4gYmFzYWwgY2VsbHMKYGBge3IgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9NCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBGaWcgNWcgZmVhdHVyZSBwbG90IChNSENfU2lnX0dheTE9IkFudGlnZW4gcHJlc2VudGF0aW9uIikgIwpGZWF0dXJlUGxvdChUQk9fc2V1cmF0LCBmZWF0dXJlcyA9IGMoIk1IQ19TaWdfR2F5MSIpLCBwdC5zaXplPTAuMiwgCiAgICAgICAgICAgIHJlZHVjdGlvbj0ndW1hcCcpICsgdmlyaWRpczo6c2NhbGVfY29sb3JfdmlyaWRpcyhvcHRpb249InJvY2tldCIsZGlyZWN0aW9uPS0xKSAmIE5vQXhlcygpCgojIyMgTk1GMy1JIHNpZ25hdHVyZSBmb3IgRmlnLiA1ZwpGZWF0dXJlUGxvdChUQk9fc2V1cmF0LCBmZWF0dXJlcyA9IGMoIk5NRjMtSTEiKSwgcHQuc2l6ZT0wLjIsIAogICAgICAgICAgICByZWR1Y3Rpb249J3VtYXAnKSArIHZpcmlkaXM6OnNjYWxlX2NvbG9yX3ZpcmlkaXMob3B0aW9uPSJyb2NrZXQiLGRpcmVjdGlvbj0tMSkgJiBOb0F4ZXMoKQoKIyMjIEdheSBldCBhbCBTQ0xDLUkgc2lnbmF0dXJlIGZvciBGaWcuIDVnCkZlYXR1cmVQbG90KFRCT19zZXVyYXQsIGZlYXR1cmVzID0gYygiR2F5X1NDTEMtSTEiKSwgcHQuc2l6ZT0wLjIsIAogICAgICAgICAgICByZWR1Y3Rpb249J3VtYXAnKSArIHZpcmlkaXM6OnNjYWxlX2NvbG9yX3ZpcmlkaXMob3B0aW9uPSJyb2NrZXQiLGRpcmVjdGlvbj0tMSkgJiBOb0F4ZXMoKQoKYGBgCgoKIyMjIyBGaWcgNWcgKHZpb2xpbiBwbG90cyBvZiBpbmZsYW1tYXRpb24gc2NvcmVzIGJ5IFNDTEMgZmF0ZSkKYGBge3IgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9My41LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwbG90VmxuQnlQaGVuKCJNSENfU2lnX0dheTEiLCB5bD1jKC0wLjEsIDAuOCkpCnBsb3RWbG5CeVBoZW4oIk5NRjMuSTEiLCB5bD1jKC0wLjEsIDAuNSkpCnBsb3RWbG5CeVBoZW4oIkdheV9TQ0xDLkkxIiwgeWw9YygtMC4xLCAwLjMpKQpgYGAKCgojIyMjIEZpZyA1aCAodmlvbGluIHBsb3RzIG9mIHRoZXJhcGV1dGljIHRhcmdldCBnZW5lIGV4cHJlc3Npb24gYnkgU0NMQyBmYXRlKQpgYGB7ciBmaWcuaGVpZ2h0PTIuNSwgZmlnLndpZHRoPTh9CnhfbGFicyA8LSBjKCJBIiwiQS9OIiwiTiIsIkF0IiwiUCIsIlNMIiwiQiIpCgp2IDwtIFZsblBsb3QoVEJPX3NldXJhdCwgZmVhdHVyZXMgPSBjKCJEbGwzIiwgIk5jYW0xIiwgIlNlejYiLCAiVGFjc3RkMiIpLCAKICAgICAgICBncm91cC5ieT1jKCJQaGVubyIpLCBjb2xzPXBoZW5vX2NvbCxhbHBoYT0wLjA1LCBuY29sPTQpCnYgPC0gbGFwcGx5KHYsICBgK2AsIGxhYnMoeD1OVUxMLCB5PSJFeHByZXNzaW9uIikpCnYgPC0gbGFwcGx5KHYsICBgK2AsIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTkwKSkpCnYgPC0gbGFwcGx5KHYsICBgK2AsICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscz14X2xhYnMpKQoKcGF0Y2h3b3JrOjp3cmFwX3Bsb3RzKHYsIG5jb2w9NCkKYGBgCiMjIyMgRXh0IERhdGEgRmlnIDZhCmBgYHtyIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTV9CkRpbVBsb3QoVEJPX3NldXJhdCwgZ3JvdXAuYnk9J0dlbm9DVCcsIGNvbHM9bXlfY29sb3JzLCBzaHVmZmxlPVRSVUUsIAogICAgICAgIHJlZHVjdGlvbj0ndW1hcCcsIGxhYmVsPUZBTFNFLCBsYWJlbC5zaXplPTYpICYgTm9BeGVzKCkgKyBOb0xlZ2VuZCgpCkRpbVBsb3QoVEJPX3NldXJhdCwgZ3JvdXAuYnk9J0dlbm9DVCcsIGNvbHM9bXlfY29sb3JzLCBzaHVmZmxlPVRSVUUsIAogICAgICAgIHJlZHVjdGlvbj0nZmEnLCBsYWJlbD1GQUxTRSwgbGFiZWwuc2l6ZT02KSAmIE5vQXhlcygpICsgTm9MZWdlbmQoKQpgYGAKCgojIyMgQ2VsbFRhZyBhbmFseXNpcyBpbiBvdGhlciBub3RlYm9vawo=